import os
import tkinter as tk
from tkinter import filedialog, ttk, messagebox, simpledialog
from tkinter.scrolledtext import ScrolledText
import re

class CodeExportTool:
    def __init__(self, root):
        self.root = root
        self.root.title("论文源代码导出工具")
        
        # 获取屏幕尺寸并设置窗口大小
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        
        # 窗口大小设为屏幕尺寸的80%，但确保最小尺寸
        window_width = max(800, int(screen_width * 0.8))
        window_height = max(600, int(screen_height * 0.8))
        
        # 设置窗口在屏幕中央
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 2
        
        self.root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
        self.root.minsize(600, 400)  # 设置最小窗口大小
        
        # 允许所有方向的调整大小
        self.root.resizable(True, True)
        
        # 使主窗口支持网格权重
        self.root.grid_columnconfigure(0, weight=1)
        self.root.grid_rowconfigure(0, weight=1)
        
        self.project_path = ""
        self.selected_files = []
        self.file_line_selections = {}  # 保存文件及选择的行
        
        self.setup_ui()
    
    def setup_ui(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 顶部控制区
        control_frame = ttk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(control_frame, text="选择项目文件夹", command=self.select_project).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="生成目录树", command=self.generate_directory_tree).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="选择要导出的文件", command=self.select_files).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="导出选中内容", command=self.export_selected).pack(side=tk.LEFT, padx=5)
        
        # 分割窗口
        paned = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 左侧目录树显示区
        tree_frame = ttk.LabelFrame(paned, text="项目结构")
        self.tree_display = ScrolledText(tree_frame, wrap=tk.WORD)
        self.tree_display.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        paned.add(tree_frame, weight=1)
        
        # 右侧预览和选择区
        preview_frame = ttk.LabelFrame(paned, text="文件预览与选择")
        
        # 文件选择下拉框
        self.file_selector_frame = ttk.Frame(preview_frame)
        self.file_selector_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(self.file_selector_frame, text="当前文件:").pack(side=tk.LEFT, padx=5)
        self.file_combo = ttk.Combobox(self.file_selector_frame, state="readonly", width=50)
        self.file_combo.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.file_combo.bind("<<ComboboxSelected>>", self.load_selected_file)
        
        # 文件内容显示区域
        self.code_display_frame = ttk.Frame(preview_frame)
        self.code_display_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 添加行号和代码显示
        self.line_numbers = tk.Text(self.code_display_frame, width=4, padx=3, takefocus=0, 
                                   border=0, background='lightgrey', state='disabled')
        self.line_numbers.pack(side=tk.LEFT, fill=tk.Y)
        
        self.code_display = ScrolledText(self.code_display_frame, wrap=tk.NONE)
        self.code_display.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 添加水平滚动条
        h_scroll = ttk.Scrollbar(preview_frame, orient=tk.HORIZONTAL, command=self.code_display.xview)
        h_scroll.pack(fill=tk.X, padx=5)
        self.code_display.config(xscrollcommand=h_scroll.set)
        
        # 行选择控制区
        selection_frame = ttk.Frame(preview_frame)
        selection_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(selection_frame, text="选择行范围", command=self.select_line_range).pack(side=tk.LEFT, padx=5)
        ttk.Button(selection_frame, text="批量应用过滤", command=self.batch_filter_files).pack(side=tk.LEFT, padx=5)
        ttk.Button(selection_frame, text="清除当前文件选择", command=self.clear_current_selection).pack(side=tk.LEFT, padx=5)
        ttk.Button(selection_frame, text="显示当前选择", command=self.show_current_selections).pack(side=tk.LEFT, padx=5)
        
        paned.add(preview_frame, weight=2)
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("准备就绪，请选择项目文件夹")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(fill=tk.X, pady=5)
        
        # 同步滚动
        self.code_display.bind("<MouseWheel>", self.on_mousewheel)
        self.code_display.bind("<KeyPress>", self.on_key_press)
        self.code_display.bind("<KeyRelease>", self.on_key_release)
    
    def on_mousewheel(self, event):
        self.update_line_numbers()
    
    def on_key_press(self, event):
        self.update_line_numbers()
    
    def on_key_release(self, event):
        self.update_line_numbers()
    
    def update_line_numbers(self):
        # 更新行号显示
        self.line_numbers.config(state='normal')
        self.line_numbers.delete(1.0, tk.END)
        
        i = 1
        for line in self.code_display.get(1.0, tk.END).split('\n'):
            self.line_numbers.insert(tk.END, f"{i}\n")
            i += 1
            
        self.line_numbers.config(state='disabled')
        
        # 确保行号和代码同步滚动
        top_index = self.code_display.index("@0,0")
        self.line_numbers.yview_moveto(float(top_index))
    
    def select_project(self):
        self.project_path = filedialog.askdirectory(title="选择项目文件夹")
        if self.project_path:
            self.status_var.set(f"已选择项目: {self.project_path}")
            self.generate_directory_tree()
    
    def generate_directory_tree(self):
        if not self.project_path:
            messagebox.showwarning("警告", "请先选择项目文件夹")
            return
        
        self.tree_display.config(state=tk.NORMAL)
        self.tree_display.delete(1.0, tk.END)
        
        self.tree_display.insert(tk.END, f"项目结构: {os.path.basename(self.project_path)}\n")
        self.tree_display.insert(tk.END, "-" * 50 + "\n")
        
        for root, dirs, files in os.walk(self.project_path):
            level = root.replace(self.project_path, '').count(os.sep)
            indent = ' ' * 4 * level
            rel_path = os.path.relpath(root, self.project_path)
            if rel_path == '.':
                continue
                
            self.tree_display.insert(tk.END, f"{indent}[文件夹] {os.path.basename(root)}/\n")
            sub_indent = ' ' * 4 * (level + 1)
            
            for file in sorted(files):
                # 过滤一些常见的二进制文件和临时文件
                if not file.endswith(('.exe', '.dll', '.obj', '.pyc', '.pyo', '.so', '.a', 
                                     '.lib', '.dylib', '.ncb', '.sdf', '.suo', '.pdb', 
                                     '.idb', '.ds_store', '.class', '.psd', '.db')):
                    self.tree_display.insert(tk.END, f"{sub_indent}[文件] {file}\n")
        
        self.tree_display.config(state=tk.DISABLED)
        self.status_var.set("目录树生成完成")
    
    def select_files(self):
        if not self.project_path:
            messagebox.showwarning("警告", "请先选择项目文件夹")
            return
        
        files = []
        for root, _, filenames in os.walk(self.project_path):
            for filename in filenames:
                # 过滤一些常见的二进制文件和临时文件
                if not filename.endswith(('.exe', '.dll', '.obj', '.pyc', '.pyo', '.so', '.a', 
                                        '.lib', '.dylib', '.ncb', '.sdf', '.suo', '.pdb', 
                                        '.idb', '.ds_store', '.class', '.psd', '.db')):
                    full_path = os.path.join(root, filename)
                    rel_path = os.path.relpath(full_path, self.project_path)
                    files.append(rel_path)
        
        if not files:
            messagebox.showinfo("信息", "项目中没有找到可导出的文件")
            return
        
        # 使用多选对话框
        selection_dialog = FileSelectionDialog(self.root, "选择要导出的文件", files)
        self.root.wait_window(selection_dialog)
        
        if selection_dialog.result:
            self.selected_files = selection_dialog.result
            self.file_combo['values'] = self.selected_files
            if self.selected_files:
                self.file_combo.current(0)
                self.load_selected_file(None)
            self.status_var.set(f"已选择 {len(self.selected_files)} 个文件")
    
    def load_selected_file(self, event):
        selected_file = self.file_combo.get()
        if not selected_file:
            return
        
        full_path = os.path.join(self.project_path, selected_file)
        
        try:
            with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
                content = f.read()
        except Exception as e:
            messagebox.showerror("错误", f"无法读取文件: {str(e)}")
            return
        
        # 显示文件内容
        self.code_display.delete(1.0, tk.END)
        self.code_display.insert(tk.END, content)
        
        # 高亮当前已选择的行
        if selected_file in self.file_line_selections:
            for start, end in self.file_line_selections[selected_file]:
                for line in range(start, end + 1):
                    start_pos = f"{line}.0"
                    end_pos = f"{line}.end"
                    self.code_display.tag_add("highlight", start_pos, end_pos)
        
        self.code_display.tag_configure("highlight", background="light blue")
        
        # 更新行号
        self.update_line_numbers()
        self.status_var.set(f"已加载文件: {selected_file}")
    
    def select_line_range(self):
        selected_file = self.file_combo.get()
        if not selected_file:
            messagebox.showwarning("警告", "请先选择一个文件")
            return
        
        # 获取文件总行数
        total_lines = int(self.code_display.index('end-1c').split('.')[0])
        
        # 获取文件内容
        file_content = self.code_display.get(1.0, tk.END)
        
        # 显示对话框让用户选择行范围
        full_path = os.path.join(self.project_path, selected_file)
        range_dialog = LineRangeDialog(self.root, "选择行范围", total_lines, full_path, file_content)
        self.root.wait_window(range_dialog)
        
        if range_dialog.result:
            # 保存选择
            if selected_file not in self.file_line_selections:
                self.file_line_selections[selected_file] = []
            
            # 添加行范围
            for start_line, end_line in range_dialog.result:
                self.file_line_selections[selected_file].append((start_line, end_line))
                
                # 高亮选择的行
                for line in range(start_line, end_line + 1):
                    start_pos = f"{line}.0"
                    end_pos = f"{line}.end"
                    self.code_display.tag_add("highlight", start_pos, end_pos)
            
            self.code_display.tag_configure("highlight", background="light blue")
            
            # 更新状态
            range_str = ", ".join([f"{start}-{end}" for start, end in range_dialog.result])
            self.status_var.set(f"已选择 {selected_file} 的行: {range_str}")
    
    def clear_current_selection(self):
        selected_file = self.file_combo.get()
        if not selected_file:
            return
        
        if selected_file in self.file_line_selections:
            del self.file_line_selections[selected_file]
        
        # 重新加载文件以清除高亮
        self.load_selected_file(None)
        self.status_var.set(f"已清除 {selected_file} 的选择")
    
    def show_current_selections(self):
        if not self.file_line_selections:
            messagebox.showinfo("信息", "当前没有选择任何行")
            return
        
        selections_text = "当前选择的文件和行范围:\n\n"
        for file, ranges in self.file_line_selections.items():
            if not ranges:
                continue
            selections_text += f"{file}:\n"
            for start, end in ranges:
                selections_text += f"  行 {start} 到 {end}\n"
        
        # 显示选择信息
        messagebox.showinfo("当前选择", selections_text)
    
    def export_selected(self):
        if not self.file_line_selections:
            messagebox.showwarning("警告", "请先选择要导出的文件和行")
            return
        
        # 弹出导出选项对话框
        export_options = ExportOptionsDialog(self.root, "导出选项")
        self.root.wait_window(export_options)
        
        if not export_options.confirmed:
            return
            
        # 获取用户的导出选项
        options = export_options.options
        
        # 选择导出文件
        export_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            title="保存导出文件"
        )
        
        if not export_path:
            return
        
        try:
            with open(export_path, 'w', encoding='utf-8') as out_file:
                if options['include_header']:
                    out_file.write("# 源代码附录\n\n")
                
                for file_path, ranges in self.file_line_selections.items():
                    if not ranges:
                        continue
                    
                    full_path = os.path.join(self.project_path, file_path)
                    
                    try:
                        with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
                            all_lines = f.readlines()
                    except Exception as e:
                        messagebox.showerror("错误", f"无法读取文件 {file_path}: {str(e)}")
                        continue
                    
                    if options['include_filenames']:
                        out_file.write(f"## {file_path}\n\n")
                    
                    if options['include_code_blocks']:
                        out_file.write("```\n")
                    
                    # 导出选定的行
                    for i, (start, end) in enumerate(ranges):
                        # 确保行号在有效范围内
                        start = max(1, start)
                        end = min(len(all_lines), end)
                        
                        # 导出选定的行
                        for line_num in range(start - 1, end):
                            out_file.write(all_lines[line_num])
                        
                        # 如果有多个范围且不是最后一个范围
                        if options['include_separators'] and i < len(ranges) - 1:
                            out_file.write("\n// ...\n\n")
                    
                    if options['include_code_blocks']:
                        out_file.write("```\n\n")
            
            messagebox.showinfo("成功", f"已成功导出到 {export_path}")
            self.status_var.set(f"导出完成: {export_path}")
            
        except Exception as e:
            messagebox.showerror("导出错误", str(e))

    def batch_filter_files(self):
        """批量应用过滤到多个文件"""
        selected_file = self.file_combo.get()
        if not selected_file:
            messagebox.showwarning("警告", "请先选择一个文件作为模板")
            return
        
        # 获取当前文件内容作为模板
        template_content = self.code_display.get(1.0, tk.END)
        full_template_path = os.path.join(self.project_path, selected_file)
        
        # 显示批量过滤对话框
        batch_dialog = BatchFilterDialog(self.root, "批量应用过滤", self.selected_files, 
                                       selected_file, full_template_path, template_content,
                                       self.project_path)
        self.root.wait_window(batch_dialog)
        
        if batch_dialog.result:
            # 应用结果
            for file_path, ranges in batch_dialog.result.items():
                if file_path not in self.file_line_selections:
                    self.file_line_selections[file_path] = []
                
                for start_line, end_line in ranges:
                    self.file_line_selections[file_path].append((start_line, end_line))
            
            # 更新当前文件的高亮
            if selected_file in self.file_line_selections:
                self.load_selected_file(None)
            
            count = sum(len(ranges) for ranges in batch_dialog.result.values())
            self.status_var.set(f"已批量应用过滤到 {len(batch_dialog.result)} 个文件，共 {count} 个选择范围")


class FileSelectionDialog(tk.Toplevel):
    def __init__(self, parent, title, file_list):
        super().__init__(parent)
        self.title(title)
        
        # 获取屏幕尺寸并设置窗口大小
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        
        # 窗口大小设为屏幕尺寸的80%，但确保最小尺寸
        window_width = max(700, int(screen_width * 0.8))
        window_height = max(500, int(screen_height * 0.8))
        
        # 设置窗口在屏幕中央
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 2
        
        self.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
        self.minsize(600, 400)  # 设置最小窗口大小
        
        # 允许调整大小
        self.resizable(True, True)
        
        self.result = []
        
        # 创建主框架
        main_frame = ttk.Frame(self)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        ttk.Label(main_frame, text="选择要导出的文件:").pack(anchor=tk.W, pady=5)
        
        # 创建上下分割窗口
        main_paned = ttk.PanedWindow(main_frame, orient=tk.VERTICAL)
        main_paned.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 创建上部水平分割窗口（目录树+文件列表）
        top_paned = ttk.PanedWindow(main_paned, orient=tk.HORIZONTAL)
        
        # 左侧目录树
        tree_frame = ttk.LabelFrame(top_paned, text="目录和文件")
        
        # 创建目录树控件
        self.tree = ttk.Treeview(tree_frame)
        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 添加滚动条
        tree_scroll_y = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
        tree_scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
        tree_scroll_x = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview)
        tree_scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        self.tree.configure(yscrollcommand=tree_scroll_y.set, xscrollcommand=tree_scroll_x.set)
        
        # 设置目录树列
        self.tree["columns"] = ("path", "type")
        self.tree.column("#0", width=200, minwidth=150)
        self.tree.column("path", width=0, stretch=tk.NO)  # 隐藏路径列
        self.tree.column("type", width=50)
        self.tree.heading("#0", text="名称")
        self.tree.heading("type", text="类型")
        
        # 添加右键菜单
        self.tree_menu = tk.Menu(self.tree, tearoff=0)
        self.tree_menu.add_command(label="展开全部", command=self.expand_all)
        self.tree_menu.add_command(label="收起全部", command=self.collapse_all)
        
        # 绑定右键菜单事件
        self.tree.bind("<Button-3>", self.show_tree_menu)
        # 绑定双击展开/收起事件
        self.tree.bind("<Double-1>", self.toggle_node)
        
        tree_frame.pack(fill=tk.BOTH, expand=True)
        
        # 右侧文件列表和过滤器
        files_frame = ttk.Frame(top_paned)
        
        # 添加文件后缀过滤功能 - 改为可折叠的设计
        self.filter_label_frame = ttk.Frame(files_frame)
        self.filter_label_frame.pack(fill=tk.X, pady=2)
        
        # 添加一个带有箭头的标签和按钮，用于折叠/展开
        self.filter_expanded = tk.BooleanVar(value=False)  # 默认折叠
        self.filter_arrow = tk.StringVar(value="▶")  # 默认折叠箭头
        
        ttk.Label(self.filter_label_frame, text="按文件类型过滤 ").pack(side=tk.LEFT)
        toggle_button = ttk.Button(self.filter_label_frame, textvariable=self.filter_arrow, 
                                 width=2, command=self.toggle_filter_panel)
        toggle_button.pack(side=tk.LEFT)
        
        # 创建过滤面板，初始隐藏
        self.extensions_frame = ttk.LabelFrame(files_frame, text="")
        
        # 添加滚动区域
        extensions_canvas = tk.Canvas(self.extensions_frame)
        scrollbar = ttk.Scrollbar(self.extensions_frame, orient=tk.VERTICAL, command=extensions_canvas.yview)
        extensions_canvas.configure(yscrollcommand=scrollbar.set)
        
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        extensions_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 文件类型过滤内容放在一个框架中，方便整体隐藏/显示
        extensions_inner_frame = ttk.Frame(extensions_canvas)
        canvas_window = extensions_canvas.create_window((0, 0), window=extensions_inner_frame, anchor=tk.NW)
        
        # 绑定框架尺寸变化事件
        extensions_inner_frame.bind("<Configure>", lambda e: extensions_canvas.configure(scrollregion=extensions_canvas.bbox("all")))
        extensions_canvas.bind("<Configure>", lambda e: extensions_canvas.itemconfig(canvas_window, width=e.width))
        
        # 设置最大高度
        extensions_canvas.configure(height=200)
        
        # 提取所有文件后缀和目录结构
        self.file_list = sorted(file_list)
        self.extensions = set()
        self.extension_vars = {}
        self.directories = {}  # 用于存储目录结构
        self.files_by_dir = {}  # 按目录存储文件
        self.staged_files = []  # 暂存的文件列表
        self.current_directories = []  # 当前选择的目录列表
        
        # 分析文件目录结构
        for file_path in self.file_list:
            # 处理文件后缀
            _, ext = os.path.splitext(file_path)
            if ext:
                self.extensions.add(ext.lower())
            
            # 处理目录结构
            dir_path = os.path.dirname(file_path)
            if dir_path not in self.files_by_dir:
                self.files_by_dir[dir_path] = []
            self.files_by_dir[dir_path].append(file_path)
            
            # 构建目录字典
            parts = file_path.split(os.sep)
            current_dict = self.directories
            current_path = ""
            
            for i, part in enumerate(parts[:-1]):  # 排除最后一个文件名
                if i == 0:
                    if part not in current_dict:
                        current_dict[part] = {"__path__": part}
                    current_path = part
                    current_dict = current_dict[part]
                else:
                    current_path = os.path.join(current_path, part)
                    if part not in current_dict:
                        current_dict[part] = {"__path__": current_path}
                    current_dict = current_dict[part]
        
        # 添加"全部"选项
        all_ext_var = tk.BooleanVar(value=True)
        self.extension_vars["全部"] = all_ext_var
        
        # 将后缀排序并添加复选框
        sorted_extensions = sorted(self.extensions)
        cols = 5  # 每行显示的复选框数量
        
        # 添加"全部"复选框
        all_cb = ttk.Checkbutton(extensions_inner_frame, text="全部", 
                               variable=all_ext_var, 
                               command=self.toggle_all_extensions)
        all_cb.grid(row=0, column=0, sticky=tk.W, padx=5)
        
        # 添加各类型文件复选框
        for i, ext in enumerate(sorted_extensions):
            row = (i + 1) // cols + 1
            col = (i + 1) % cols
            ext_var = tk.BooleanVar(value=True)
            self.extension_vars[ext] = ext_var
            cb = ttk.Checkbutton(extensions_inner_frame, text=ext, 
                               variable=ext_var, 
                               command=self.update_file_list)
            cb.grid(row=row, column=col, sticky=tk.W, padx=5)
        
        # 默认不显示过滤面板
        if not self.filter_expanded.get():
            self.extensions_frame.pack_forget()
        else:
            self.extensions_frame.pack(fill=tk.X, pady=5)
        
        # 文本过滤功能
        filter_frame = ttk.Frame(files_frame)
        filter_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(filter_frame, text="文本过滤:").pack(side=tk.LEFT)
        self.filter_var = tk.StringVar()
        self.filter_var.trace("w", self.update_filter)
        filter_entry = ttk.Entry(filter_frame, textvariable=self.filter_var)
        filter_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        # 状态信息
        self.status_var = tk.StringVar()
        self.status_var.set("准备就绪，请选择文件或目录")
        status_label = ttk.Label(files_frame, textvariable=self.status_var, anchor=tk.W)
        status_label.pack(fill=tk.X, pady=5)
        
        # 文件列表框
        list_frame = ttk.LabelFrame(files_frame, text="文件列表")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 添加列表操作按钮
        list_buttons_frame = ttk.Frame(list_frame)
        list_buttons_frame.pack(fill=tk.X, pady=2)
        
        ttk.Button(list_buttons_frame, text="全选", command=self.select_all_files).pack(side=tk.LEFT, padx=2)
        ttk.Button(list_buttons_frame, text="取消全选", command=self.deselect_all_files).pack(side=tk.LEFT, padx=2)
        ttk.Button(list_buttons_frame, text="添加到暂存区", command=self.add_to_staging).pack(side=tk.LEFT, padx=2)
        
        # 文件列表
        list_content_frame = ttk.Frame(list_frame)
        list_content_frame.pack(fill=tk.BOTH, expand=True)
        
        scrollbar_y = ttk.Scrollbar(list_content_frame)
        scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
        
        scrollbar_x = ttk.Scrollbar(list_content_frame, orient=tk.HORIZONTAL)
        scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)
        
        self.listbox = tk.Listbox(list_content_frame, selectmode=tk.MULTIPLE, xscrollcommand=scrollbar_x.set)
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.config(yscrollcommand=scrollbar_y.set)
        scrollbar_y.config(command=self.listbox.yview)
        scrollbar_x.config(command=self.listbox.xview)
        
        # 添加到top_paned
        top_paned.add(tree_frame, weight=1)
        top_paned.add(files_frame, weight=2)
        
        # 下部暂存区
        staging_frame = ttk.LabelFrame(main_paned, text="暂存区 (已选择的文件)")
        
        # 暂存区按钮
        staging_buttons_frame = ttk.Frame(staging_frame)
        staging_buttons_frame.pack(fill=tk.X, pady=2)
        
        ttk.Button(staging_buttons_frame, text="全选", command=self.select_all_staged).pack(side=tk.LEFT, padx=2)
        ttk.Button(staging_buttons_frame, text="取消全选", command=self.deselect_all_staged).pack(side=tk.LEFT, padx=2)
        ttk.Button(staging_buttons_frame, text="从暂存区移除", command=self.remove_from_staging).pack(side=tk.LEFT, padx=2)
        ttk.Button(staging_buttons_frame, text="清空暂存区", command=self.clear_staging).pack(side=tk.LEFT, padx=2)
        
        # 暂存文件列表
        staging_list_frame = ttk.Frame(staging_frame)
        staging_list_frame.pack(fill=tk.BOTH, expand=True)
        
        scrollbar_staged_y = ttk.Scrollbar(staging_list_frame)
        scrollbar_staged_y.pack(side=tk.RIGHT, fill=tk.Y)
        
        scrollbar_staged_x = ttk.Scrollbar(staging_list_frame, orient=tk.HORIZONTAL)
        scrollbar_staged_x.pack(side=tk.BOTTOM, fill=tk.X)
        
        self.staging_listbox = tk.Listbox(staging_list_frame, selectmode=tk.MULTIPLE, xscrollcommand=scrollbar_staged_x.set)
        self.staging_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.staging_listbox.config(yscrollcommand=scrollbar_staged_y.set)
        scrollbar_staged_y.config(command=self.staging_listbox.yview)
        scrollbar_staged_x.config(command=self.staging_listbox.xview)
        
        # 添加到main_paned
        main_paned.add(top_paned, weight=2)
        main_paned.add(staging_frame, weight=1)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        ttk.Label(button_frame, text="暂存区文件数:").pack(side=tk.LEFT, padx=5)
        self.staged_count_var = tk.StringVar(value="0")
        ttk.Label(button_frame, textvariable=self.staged_count_var).pack(side=tk.LEFT, padx=5)
        
        ttk.Button(button_frame, text="确定", command=self.on_ok).pack(side=tk.RIGHT, padx=5)
        ttk.Button(button_frame, text="取消", command=self.on_cancel).pack(side=tk.RIGHT, padx=5)
        
        # 初始化目录树和文件列表
        self.build_directory_tree()
        self.filtered_list = []
        self.update_file_list()
        
        # 绑定目录树选择事件
        self.tree.bind("<<TreeviewSelect>>", self.on_tree_select)
        # 绑定双击事件
        self.tree.bind("<Double-1>", self.on_tree_double_click)
        self.listbox.bind("<Double-1>", self.on_listbox_double_click)
        # 绑定listbox选择事件
        self.listbox.bind("<<ListboxSelect>>", self.on_listbox_select)
        
        # 添加搜索框
        search_frame = ttk.Frame(files_frame)
        search_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(search_frame, text="搜索文件:").pack(side=tk.LEFT)
        self.search_var = tk.StringVar()
        self.search_entry = ttk.Entry(search_frame, textvariable=self.search_var)
        self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.search_entry.bind("<Return>", lambda e: self.search_files())
        
        ttk.Button(search_frame, text="搜索", command=self.search_files).pack(side=tk.LEFT, padx=5)
        ttk.Button(search_frame, text="清除", command=self.clear_search).pack(side=tk.LEFT, padx=5)
        
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.on_cancel)
    
    def build_directory_tree(self):
        """构建目录树视图，包括文件"""
        # 清空现有树
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        # 添加根节点
        root_id = self.tree.insert("", "end", text="根目录", open=True, values=["", "目录"])
        
        # 添加"显示所有文件"选项
        self.tree.insert(root_id, "end", text="显示所有文件", values=["", "选项"])
        
        # 递归添加目录和文件
        def add_directories(parent_id, directory_dict, path_prefix=""):
            for key, value in sorted(directory_dict.items()):
                if key != "__path__":
                    dir_path = value.get("__path__", "")
                    item_id = self.tree.insert(parent_id, "end", text=key, values=[dir_path, "目录"], open=False)
                    
                    # 添加当前目录下的文件
                    if dir_path in self.files_by_dir:
                        file_dict = {}
                        for file_path in self.files_by_dir[dir_path]:
                            file_name = os.path.basename(file_path)
                            file_dict[file_name] = file_path
                        
                        for file_name, file_path in sorted(file_dict.items()):
                            _, ext = os.path.splitext(file_name)
                            self.tree.insert(item_id, "end", text=file_name, values=[file_path, "文件"])
                    
                    # 递归添加子目录
                    add_directories(item_id, value, dir_path)
        
        # 添加顶级目录和文件
        for key, value in sorted(self.directories.items()):
            dir_path = value.get("__path__", "")
            item_id = self.tree.insert(root_id, "end", text=key, values=[dir_path, "目录"], open=False)
            
            # 添加当前目录下的文件
            if dir_path in self.files_by_dir:
                file_dict = {}
                for file_path in self.files_by_dir[dir_path]:
                    if os.path.dirname(file_path) == dir_path:  # 确保文件直接在当前目录下
                        file_name = os.path.basename(file_path)
                        file_dict[file_name] = file_path
                
                for file_name, file_path in sorted(file_dict.items()):
                    _, ext = os.path.splitext(file_name)
                    self.tree.insert(item_id, "end", text=file_name, values=[file_path, "文件"])
            
            add_directories(item_id, value, dir_path)
    
    def on_tree_select(self, event):
        """处理目录树选择事件"""
        selected_items = self.tree.selection()
        if not selected_items:
            return
            
        self.current_directories = []
        selected_files = []
        
        for item in selected_items:
            item_type = self.tree.item(item, "values")[1]
            item_path = self.tree.item(item, "values")[0]
            item_text = self.tree.item(item, "text")
            
            if item_text == "显示所有文件":
                # 显示所有文件
                self.current_directories = []
                self.status_var.set("显示所有文件")
                break
            elif item_type == "目录":
                # 选择了目录
                self.current_directories.append(item_path)
                self.status_var.set(f"已选择 {len(self.current_directories)} 个目录")
            elif item_type == "文件":
                # 选择了文件
                selected_files.append(item_path)
        
        # 更新文件列表
        self.update_file_list()
        
        # 处理直接选择的文件
        if selected_files:
            for file_path in selected_files:
                if file_path not in self.staged_files:
                    self.staged_files.append(file_path)
            self.update_staging_list()
            self.status_var.set(f"已添加 {len(selected_files)} 个文件到暂存区")
    
    def on_tree_double_click(self, event):
        """处理目录树双击事件"""
        item = self.tree.identify("item", event.x, event.y)
        if not item:
            return
            
        item_type = self.tree.item(item, "values")[1]
        item_path = self.tree.item(item, "values")[0]
        
        if item_type == "文件" and item_path:
            # 双击文件时添加到暂存区
            if item_path not in self.staged_files:
                self.staged_files.append(item_path)
                self.update_staging_list()
                self.status_var.set(f"已添加文件到暂存区: {os.path.basename(item_path)}")
    
    def on_listbox_double_click(self, event):
        """处理文件列表双击事件"""
        selection = self.listbox.curselection()
        if not selection:
            return
            
        index = selection[0]
        if index < len(self.filtered_list):
            file_path = self.filtered_list[index]
            if file_path not in self.staged_files:
                self.staged_files.append(file_path)
                self.update_staging_list()
                self.status_var.set(f"已添加文件到暂存区: {os.path.basename(file_path)}")
    
    def toggle_all_extensions(self):
        """全选或取消全选所有文件类型"""
        all_selected = self.extension_vars["全部"].get()
        for ext, var in self.extension_vars.items():
            if ext != "全部":
                var.set(all_selected)
        self.update_file_list()
    
    def update_file_list(self):
        """根据选择的目录、文件类型和文本过滤更新文件列表"""
        # 检查是否所有类型都被选中
        all_selected = all(var.get() for ext, var in self.extension_vars.items() if ext != "全部")
        self.extension_vars["全部"].set(all_selected)
        
        # 根据目录、后缀和文本过滤更新列表
        self.listbox.delete(0, tk.END)
        self.filtered_list = []
        
        filter_text = self.filter_var.get().lower()
        
        # 决定显示哪些文件
        files_to_show = []
        
        if not self.current_directories:
            # 显示所有文件
            files_to_show = self.file_list
        else:
            # 显示选定目录下的文件
            for dir_path in self.current_directories:
                for file_path in self.file_list:
                    if file_path.startswith(dir_path):
                        files_to_show.append(file_path)
        
        # 应用过滤器
        for file in files_to_show:
            # 检查文件类型
            _, ext = os.path.splitext(file)
            ext = ext.lower()
            
            # 检查文件类型是否被选中
            if (ext in self.extension_vars and self.extension_vars[ext].get()) or self.extension_vars["全部"].get():
                # 检查文本过滤
                if filter_text and filter_text not in file.lower():
                    continue
                
                self.filtered_list.append(file)
                self.listbox.insert(tk.END, file)
        
        # 更新状态
        if self.current_directories:
            dir_names = [os.path.basename(d) for d in self.current_directories]
            self.status_var.set(f"当前目录: {', '.join(dir_names)} - 显示 {len(self.filtered_list)} 个文件")
        else:
            self.status_var.set(f"显示所有文件 - 共 {len(self.filtered_list)} 个")
    
    def update_filter(self, *args):
        """文本过滤更改时更新列表"""
        self.update_file_list()
    
    def select_all_files(self):
        """选择当前过滤列表中的所有文件"""
        self.listbox.select_set(0, tk.END)
    
    def deselect_all_files(self):
        """取消选择当前列表中的所有文件"""
        self.listbox.selection_clear(0, tk.END)
    
    def select_all_staged(self):
        """选择暂存区中的所有文件"""
        self.staging_listbox.select_set(0, tk.END)
    
    def deselect_all_staged(self):
        """取消选择暂存区中的所有文件"""
        self.staging_listbox.selection_clear(0, tk.END)
    
    def add_to_staging(self):
        """将选中的文件添加到暂存区"""
        selection = self.listbox.curselection()
        added_count = 0
        
        for index in selection:
            if index < len(self.filtered_list):
                file_path = self.filtered_list[index]
                if file_path not in self.staged_files:
                    self.staged_files.append(file_path)
                    added_count += 1
        
        if added_count > 0:
            self.update_staging_list()
            self.status_var.set(f"已添加 {added_count} 个文件到暂存区")
    
    def remove_from_staging(self):
        """从暂存区移除选中的文件"""
        selection = list(self.staging_listbox.curselection())
        if not selection:
            return
        
        # 从后往前删除，避免索引变化
        for index in sorted(selection, reverse=True):
            if index < len(self.staged_files):
                del self.staged_files[index]
        
        self.update_staging_list()
        self.status_var.set(f"已从暂存区移除 {len(selection)} 个文件")
    
    def clear_staging(self):
        """清空暂存区"""
        self.staged_files = []
        self.update_staging_list()
        self.status_var.set("已清空暂存区")
    
    def update_staging_list(self):
        """更新暂存区列表显示"""
        self.staging_listbox.delete(0, tk.END)
        for file in self.staged_files:
            self.staging_listbox.insert(tk.END, file)
        
        # 更新暂存文件计数
        self.staged_count_var.set(str(len(self.staged_files)))
    
    def on_ok(self):
        """确认选择"""
        if not self.staged_files:
            if messagebox.askyesno("确认", "暂存区为空，确定不选择任何文件吗？"):
                self.result = []
                self.destroy()
        else:
            self.result = self.staged_files.copy()
            self.destroy()
    
    def on_cancel(self):
        """取消选择"""
        self.result = []
        self.destroy()
    
    def on_listbox_select(self, event):
        """处理文件列表选择事件，在目录树中定位选中的文件"""
        selection = self.listbox.curselection()
        if not selection:
            return
            
        index = selection[0]
        if index < len(self.filtered_list):
            file_path = self.filtered_list[index]
            self.locate_file_in_tree(file_path)
    
    def locate_file_in_tree(self, file_path):
        """在目录树中定位并展开指定的文件路径"""
        # 先清除目录树的已选项
        self.tree.selection_remove(self.tree.selection())
        
        # 获取文件所在目录
        dir_path = os.path.dirname(file_path)
        file_name = os.path.basename(file_path)
        
        # 展开根节点
        root_item = self.tree.get_children()[0]
        self.tree.item(root_item, open=True)
        
        # 查找目录路径
        path_parts = dir_path.split(os.sep)
        current_item = root_item
        found = False
        
        # 找到包含第一级目录的节点
        for child in self.tree.get_children(current_item):
            if self.tree.item(child, "text") == path_parts[0]:
                current_item = child
                self.tree.item(current_item, open=True)
                found = True
                break
        
        if not found:
            self.status_var.set(f"无法在目录树中找到: {dir_path}")
            return
            
        # 继续查找剩余的目录层级
        for i in range(1, len(path_parts)):
            found = False
            for child in self.tree.get_children(current_item):
                if self.tree.item(child, "text") == path_parts[i]:
                    current_item = child
                    self.tree.item(current_item, open=True)
                    found = True
                    break
            
            if not found:
                break
        
        # 查找并选中文件
        if found:
            for child in self.tree.get_children(current_item):
                if self.tree.item(child, "text") == file_name and self.tree.item(child, "values")[1] == "文件":
                    self.tree.see(child)  # 确保节点可见
                    self.tree.selection_set(child)  # 选中节点
                    self.status_var.set(f"已定位文件: {file_path}")
                    return
        
        # 如果找到了目录但没找到文件，至少显示目录
        self.tree.see(current_item)
        self.status_var.set(f"已定位到目录: {dir_path}")
    
    def expand_all(self):
        """展开所有节点"""
        # 递归展开所有节点
        def expand_children(node):
            children = self.tree.get_children(node)
            for child in children:
                self.tree.item(child, open=True)
                expand_children(child)
        
        # 展开根节点下的所有节点
        root_nodes = self.tree.get_children()
        for node in root_nodes:
            self.tree.item(node, open=True)
            expand_children(node)
    
    def collapse_all(self):
        """收起所有节点"""
        # 递归收起所有节点
        def collapse_children(node):
            children = self.tree.get_children(node)
            for child in children:
                self.tree.item(child, open=False)
                collapse_children(child)
        
        # 收起根节点下的所有节点（保持根节点展开）
        root_nodes = self.tree.get_children()
        for node in root_nodes:
            if node != root_nodes[0]:  # 保持根节点展开
                self.tree.item(node, open=False)
            collapse_children(node)
    
    def toggle_node(self, event):
        """双击切换节点展开/收起状态"""
        # 获取点击的项
        item = self.tree.identify_row(event.y)
        if item:
            # 获取当前状态
            is_open = self.tree.item(item, "open")
            # 切换状态
            self.tree.item(item, open=not is_open)
    
    def show_tree_menu(self, event):
        """显示目录树右键菜单"""
        # 获取点击的项
        item = self.tree.identify_row(event.y)
        if item:
            # 选中当前项
            self.tree.selection_set(item)
            # 在点击位置显示菜单
            self.tree_menu.post(event.x_root, event.y_root)
    
    def search_files(self):
        """搜索文件"""
        search_text = self.search_var.get().lower()
        if not search_text:
            return
            
        self.file_listbox.delete(0, tk.END)
        self.filtered_list = []
        
        for file in self.file_list:
            if search_text in file.lower():
                self.filtered_list.append(file)
                self.file_listbox.insert(tk.END, file)
        
        if not self.filtered_list:
            messagebox.showinfo("搜索结果", "没有找到匹配的文件")
        else:
            self.status_var.set(f"找到 {len(self.filtered_list)} 个匹配文件")
    
    def clear_search(self):
        """清除搜索结果"""
        self.search_var.set("")
        self.filtered_list = self.file_list.copy()
        
        self.file_listbox.delete(0, tk.END)
        for file in self.filtered_list:
            self.file_listbox.insert(tk.END, file)
            
        self.status_var.set("搜索已清除")
    
    def toggle_filter_panel(self):
        """切换文件类型过滤面板的显示/隐藏状态"""
        # 切换状态
        current_state = self.filter_expanded.get()
        self.filter_expanded.set(not current_state)
        
        # 根据状态显示/隐藏过滤面板
        if self.filter_expanded.get():
            self.filter_arrow.set("▼")  # 展开状态箭头
            self.extensions_frame.pack(fill=tk.X, pady=5, after=self.filter_label_frame)
        else:
            self.filter_arrow.set("▶")  # 折叠状态箭头
            self.extensions_frame.pack_forget()
        
        # 调整窗口大小，确保所有内容可见
        self.update_idletasks()


class LineRangeDialog(tk.Toplevel):
    def __init__(self, parent, title, total_lines, file_path, file_content):
        super().__init__(parent)
        self.title(title)
        
        # 获取屏幕尺寸并设置窗口大小
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        
        # 窗口大小设为屏幕尺寸的70%，但确保最小尺寸
        window_width = max(700, int(screen_width * 0.7))
        window_height = max(500, int(screen_height * 0.7))
        
        # 设置窗口在屏幕中央
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 2
        
        self.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
        self.minsize(600, 400)  # 设置最小窗口大小
        
        # 允许调整大小
        self.resizable(True, True)
        
        self.result = None
        self.total_lines = total_lines
        self.file_path = file_path
        self.file_content = file_content.split('\n')
        self.filtered_lines = list(range(1, total_lines + 1))  # 初始包含所有行
        
        # 创建主框架
        main_frame = ttk.Frame(self, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建标题标签
        ttk.Label(main_frame, text=f"选择 {os.path.basename(file_path)} 的行范围:").grid(
            row=0, column=0, columnspan=4, sticky=tk.W, pady=5)
        
        # 创建上下分割窗口
        paned = ttk.PanedWindow(main_frame, orient=tk.VERTICAL)
        paned.grid(row=1, column=0, columnspan=4, sticky=(tk.N, tk.S, tk.E, tk.W), pady=5)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(1, weight=1)
        
        # 上部过滤选项
        filter_frame = ttk.LabelFrame(paned, text="智能过滤选项")
        
        # 过滤选项
        filter_options_frame = ttk.Frame(filter_frame)
        filter_options_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 文件类型特定过滤
        _, ext = os.path.splitext(file_path)
        ext = ext.lower()
        
        # 通用过滤选项
        self.filter_imports_var = tk.BooleanVar(value=False)
        self.filter_empty_lines_var = tk.BooleanVar(value=False)
        
        ttk.Checkbutton(filter_options_frame, text="过滤导入语句", 
                      variable=self.filter_imports_var,
                      command=self.apply_filters).grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        
        ttk.Checkbutton(filter_options_frame, text="过滤空白行", 
                      variable=self.filter_empty_lines_var,
                      command=self.apply_filters).grid(row=0, column=1, sticky=tk.W, padx=5, pady=2)
        
        # 特定文件类型的过滤选项
        self.language_specific_vars = []
        
        # Java 特定过滤
        if ext in ['.java', '.kt', '.scala']:
            self.filter_annotations_var = tk.BooleanVar(value=False)
            ttk.Checkbutton(filter_options_frame, text="过滤注解(@开头)", 
                          variable=self.filter_annotations_var,
                          command=self.apply_filters).grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
            self.language_specific_vars.append(('annotations', self.filter_annotations_var))
            
            self.filter_comments_var = tk.BooleanVar(value=False)
            ttk.Checkbutton(filter_options_frame, text="过滤注释", 
                          variable=self.filter_comments_var,
                          command=self.apply_filters).grid(row=0, column=3, sticky=tk.W, padx=5, pady=2)
            self.language_specific_vars.append(('comments', self.filter_comments_var))
        
        # HTML/Vue 特定过滤
        elif ext in ['.html', '.vue', '.jsx', '.tsx']:
            self.filter_html_head_var = tk.BooleanVar(value=False)
            ttk.Checkbutton(filter_options_frame, text="过滤头部", 
                          variable=self.filter_html_head_var,
                          command=self.apply_filters).grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
            self.language_specific_vars.append(('html_head', self.filter_html_head_var))
            
            self.filter_scripts_var = tk.BooleanVar(value=False)
            ttk.Checkbutton(filter_options_frame, text="只保留主要内容", 
                          variable=self.filter_scripts_var,
                          command=self.apply_filters).grid(row=0, column=3, sticky=tk.W, padx=5, pady=2)
            self.language_specific_vars.append(('scripts', self.filter_scripts_var))
        
        # CSS/SCSS/LESS 特定过滤
        elif ext in ['.css', '.scss', '.less']:
            self.filter_vendor_prefixes_var = tk.BooleanVar(value=False)
            ttk.Checkbutton(filter_options_frame, text="过滤浏览器前缀", 
                          variable=self.filter_vendor_prefixes_var,
                          command=self.apply_filters).grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
            self.language_specific_vars.append(('vendor_prefixes', self.filter_vendor_prefixes_var))
        
        # 自定义过滤
        custom_filter_frame = ttk.Frame(filter_frame)
        custom_filter_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(custom_filter_frame, text="自定义过滤正则表达式:").pack(side=tk.LEFT, padx=5)
        self.custom_regex_var = tk.StringVar()
        self.custom_regex_entry = ttk.Entry(custom_filter_frame, textvariable=self.custom_regex_var, width=30)
        self.custom_regex_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        # 智能过滤按钮
        filter_buttons_frame = ttk.Frame(filter_frame)
        filter_buttons_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(filter_buttons_frame, text="智能检测核心代码", 
                 command=self.auto_detect_core_code).pack(side=tk.LEFT, padx=5)
        ttk.Button(filter_buttons_frame, text="重置所有过滤", 
                 command=self.reset_filters).pack(side=tk.LEFT, padx=5)
        
        # 添加过滤框架到分割窗口
        paned.add(filter_frame, weight=1)
        
        # 下部预览区域
        preview_frame = ttk.LabelFrame(paned, text="代码预览")
        
        preview_content_frame = ttk.Frame(preview_frame)
        preview_content_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 行号显示
        self.line_numbers = tk.Text(preview_content_frame, width=5, padx=3, takefocus=0,
                                  border=0, background='lightgrey', state='disabled')
        self.line_numbers.pack(side=tk.LEFT, fill=tk.Y)
        
        # 代码预览区
        self.preview_text = ScrolledText(preview_content_frame, wrap=tk.NONE)
        self.preview_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 水平滚动条
        h_scroll = ttk.Scrollbar(preview_frame, orient=tk.HORIZONTAL, command=self.preview_text.xview)
        h_scroll.pack(fill=tk.X, padx=5)
        self.preview_text.config(xscrollcommand=h_scroll.set)
        
        # 同步滚动
        self.preview_text.bind("<MouseWheel>", self.on_preview_scroll)
        self.preview_text.bind("<KeyPress>", self.on_preview_scroll)
        self.preview_text.bind("<KeyRelease>", self.on_preview_scroll)
        
        # 添加预览框架到分割窗口
        paned.add(preview_frame, weight=3)
        
        # 手动选择行范围
        manual_frame = ttk.LabelFrame(main_frame, text="手动选择范围")
        manual_frame.grid(row=2, column=0, columnspan=4, sticky=(tk.E, tk.W), pady=5)
        
        ttk.Label(manual_frame, text="开始行:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.start_var = tk.StringVar(value="1")
        ttk.Entry(manual_frame, textvariable=self.start_var, width=10).grid(row=0, column=1, sticky=tk.W, pady=5, padx=5)
        
        ttk.Label(manual_frame, text="结束行:").grid(row=0, column=2, sticky=tk.W, pady=5)
        self.end_var = tk.StringVar(value=str(total_lines))
        ttk.Entry(manual_frame, textvariable=self.end_var, width=10).grid(row=0, column=3, sticky=tk.W, pady=5, padx=5)
        
        ttk.Button(manual_frame, text="应用范围", 
                 command=self.apply_manual_range).grid(row=0, column=4, padx=5, pady=5)
        
        # 状态栏
        self.status_var = tk.StringVar(value=f"总行数: {total_lines}, 当前选择: {len(self.filtered_lines)} 行")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.grid(row=3, column=0, columnspan=4, sticky=(tk.E, tk.W), pady=5)
        
        # 底部按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=4, column=0, columnspan=4, pady=10)
        
        ttk.Button(button_frame, text="全选", command=self.select_all_lines).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="确定", command=self.on_ok).pack(side=tk.RIGHT, padx=5)
        ttk.Button(button_frame, text="取消", command=self.on_cancel).pack(side=tk.RIGHT, padx=5)
        
        # 初始显示所有代码
        self.update_preview()
        
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.on_cancel)
    
    def on_preview_scroll(self, event=None):
        """处理预览区滚动，同步行号"""
        self.update_line_numbers()
    
    def update_line_numbers(self):
        """更新行号显示"""
        self.line_numbers.config(state='normal')
        self.line_numbers.delete(1.0, tk.END)
        
        # 获取当前显示的行号
        lines = []
        for i, line_num in enumerate(self.filtered_lines):
            lines.append(str(line_num))
            
        self.line_numbers.insert(tk.END, "\n".join(lines))
        self.line_numbers.config(state='disabled')
        
        # 同步滚动
        top_index = self.preview_text.index("@0,0")
        if "." in top_index:
            top_line = int(top_index.split('.')[0])
            self.line_numbers.yview_moveto((top_line - 1) / len(self.filtered_lines))
    
    def apply_filters(self):
        """应用所有选中的过滤器"""
        # 重置过滤行列表
        self.filtered_lines = list(range(1, self.total_lines + 1))
        
        # 应用导入语句过滤
        if self.filter_imports_var.get():
            self.filter_imports()
        
        # 应用空白行过滤
        if self.filter_empty_lines_var.get():
            self.filter_empty_lines()
        
        # 应用特定语言过滤
        for filter_type, var in self.language_specific_vars:
            if var.get():
                if filter_type == 'annotations':
                    self.filter_annotations()
                elif filter_type == 'comments':
                    self.filter_comments()
                elif filter_type == 'html_head':
                    self.filter_html_head()
                elif filter_type == 'scripts':
                    self.filter_keep_main_content()
                elif filter_type == 'vendor_prefixes':
                    self.filter_vendor_prefixes()
        
        # 应用自定义正则过滤
        custom_regex = self.custom_regex_var.get().strip()
        if custom_regex:
            try:
                pattern = re.compile(custom_regex)
                self.filtered_lines = [i for i in self.filtered_lines 
                                     if i <= len(self.file_content) and not pattern.search(self.file_content[i-1])]
            except re.error:
                messagebox.showerror("正则表达式错误", "您输入的正则表达式无效，请修正后重试。")
        
        # 更新预览
        self.update_preview()
    
    def filter_imports(self):
        """过滤导入语句"""
        # 处理Java, Python等常见语言的导入
        import_patterns = [
            r'^\s*import\s+', 
            r'^\s*from\s+.+\s+import\s+',
            r'^\s*require\s*\(',
            r'^\s*#include\s+',
            r'^\s*using\s+',
            r'^\s*@import\s+'
        ]
        combined_pattern = re.compile('|'.join(import_patterns))
        
        self.filtered_lines = [i for i in self.filtered_lines 
                              if i > len(self.file_content) or not combined_pattern.match(self.file_content[i-1])]
    
    def filter_empty_lines(self):
        """过滤空白行"""
        self.filtered_lines = [i for i in self.filtered_lines 
                              if i > len(self.file_content) or self.file_content[i-1].strip()]
    
    def filter_annotations(self):
        """过滤Java注解等"""
        annotation_pattern = re.compile(r'^\s*@\w+')
        self.filtered_lines = [i for i in self.filtered_lines 
                              if i > len(self.file_content) or not annotation_pattern.match(self.file_content[i-1])]
    
    def filter_comments(self):
        """过滤注释"""
        # 处理多种语言的注释格式
        comment_patterns = [
            r'^\s*\/\/.*$',  # Java, JavaScript等单行注释
            r'^\s*#.*$',     # Python, Shell等单行注释
            r'^\s*--.*$',    # SQL, Lua等单行注释
            r'^\s*\/\*.*\*\/\s*$', # 单行多行注释
            r'^\s*\*.*$'     # 多行注释的中间行
        ]
        combined_pattern = re.compile('|'.join(comment_patterns))
        
        # 找出所有多行注释的行
        in_multiline_comment = False
        multiline_comment_lines = set()
        
        for i, line in enumerate(self.file_content):
            if re.search(r'\/\*', line) and not re.search(r'\*\/', line):
                in_multiline_comment = True
                multiline_comment_lines.add(i + 1)
            elif in_multiline_comment:
                multiline_comment_lines.add(i + 1)
                if re.search(r'\*\/', line):
                    in_multiline_comment = False
        
        # 过滤注释行
        self.filtered_lines = [i for i in self.filtered_lines 
                             if i > len(self.file_content) 
                             or (not combined_pattern.match(self.file_content[i-1]) and i not in multiline_comment_lines)]
    
    def filter_html_head(self):
        """过滤HTML/Vue头部"""
        if not any('<head>' in line for line in self.file_content):
            return
            
        in_head = False
        head_lines = set()
        
        for i, line in enumerate(self.file_content):
            if '<head>' in line:
                in_head = True
                head_lines.add(i + 1)
            elif in_head:
                head_lines.add(i + 1)
                if '</head>' in line:
                    in_head = False
        
        self.filtered_lines = [i for i in self.filtered_lines if i not in head_lines]
    
    def filter_keep_main_content(self):
        """只保留HTML/Vue/JSX主要内容"""
        _, ext = os.path.splitext(self.file_path)
        ext = ext.lower()
        
        # 检测文件类型并决定主要区域
        if ext == '.vue':
            # Vue文件尝试保留template部分
            in_template = False
            keep_lines = set()
            
            for i, line in enumerate(self.file_content):
                if '<template>' in line:
                    in_template = True
                    keep_lines.add(i + 1)
                elif in_template:
                    keep_lines.add(i + 1)
                    if '</template>' in line:
                        in_template = False
            
            if keep_lines:
                self.filtered_lines = [i for i in self.filtered_lines if i in keep_lines]
        
        elif ext in ['.html', '.jsx', '.tsx']:
            # HTML/JSX可能需要保留body或主要组件部分
            body_pattern = re.compile(r'<body.*?>|<div.*?id="app"|<div.*?class="container"|class="main"')
            end_pattern = re.compile(r'</body>|</div>')
            
            in_main_content = False
            main_content_start = 0
            keep_lines = set()
            
            for i, line in enumerate(self.file_content):
                if not in_main_content and body_pattern.search(line):
                    in_main_content = True
                    main_content_start = i
                    keep_lines.add(i + 1)
                elif in_main_content:
                    keep_lines.add(i + 1)
                    if end_pattern.search(line) and i - main_content_start > 5:  # 确保不是小div
                        in_main_content = False
            
            if keep_lines:
                self.filtered_lines = [i for i in self.filtered_lines if i in keep_lines]
    
    def filter_vendor_prefixes(self):
        """过滤CSS浏览器前缀"""
        vendor_pattern = re.compile(r'^\s*(-webkit-|-moz-|-ms-|-o-)')
        self.filtered_lines = [i for i in self.filtered_lines 
                             if i > len(self.file_content) or not vendor_pattern.match(self.file_content[i-1])]
    
    def auto_detect_core_code(self):
        """自动检测核心代码"""
        _, ext = os.path.splitext(self.file_path)
        ext = ext.lower()
        
        # 重置过滤
        self.reset_filters()
        
        # 应用基本过滤
        self.filter_imports_var.set(True)
        self.filter_empty_lines_var.set(True)
        
        # 文件类型特定处理
        if ext in ['.java', '.kt', '.scala']:
            # 对于Java文件，检测并保留方法和主要代码块
            # 这里实现一个简单的算法找出方法体
            class_pattern = re.compile(r'^\s*(public|private|protected)?\s*(class|interface|enum)\s+\w+')
            method_pattern = re.compile(r'^\s*(public|private|protected|static|final|abstract)?\s*\w+(<.*>)?\s+\w+\s*\(')
            
            in_class = False
            class_braces = 0
            method_lines = set()
            
            for i, line in enumerate(self.file_content):
                if class_pattern.match(line):
                    in_class = True
                    method_lines.add(i + 1)
                    if '{' in line:
                        class_braces += 1
                elif in_class:
                    if '{' in line:
                        class_braces += 1
                    if '}' in line:
                        class_braces -= 1
                        if class_braces == 0:
                            in_class = False
                    
                    if method_pattern.match(line) or class_braces > 1:
                        method_lines.add(i + 1)
            
            if method_lines:
                self.filtered_lines = [i for i in self.filtered_lines if i in method_lines]
            
            # 设置其他Java相关过滤
            for filter_type, var in self.language_specific_vars:
                if filter_type in ['annotations', 'comments']:
                    var.set(True)
        
        elif ext in ['.html', '.vue', '.jsx', '.tsx']:
            # 应用HTML/Vue特定过滤
            for filter_type, var in self.language_specific_vars:
                if filter_type in ['html_head', 'scripts']:
                    var.set(True)
        
        elif ext in ['.css', '.scss', '.less']:
            # 应用CSS特定过滤
            for filter_type, var in self.language_specific_vars:
                if filter_type == 'vendor_prefixes':
                    var.set(True)
        
        # 更新预览
        self.apply_filters()
    
    def reset_filters(self):
        """重置所有过滤器"""
        self.filter_imports_var.set(False)
        self.filter_empty_lines_var.set(False)
        self.custom_regex_var.set("")
        
        for _, var in self.language_specific_vars:
            var.set(False)
        
        self.filtered_lines = list(range(1, self.total_lines + 1))
        self.update_preview()
    
    def apply_manual_range(self):
        """应用手动输入的行范围"""
        try:
            start = int(self.start_var.get())
            end = int(self.end_var.get())
            
            if start < 1 or end > self.total_lines or start > end:
                messagebox.showerror("错误", f"请输入有效的行范围 (1-{self.total_lines})")
                return
            
            # 过滤行范围
            self.filtered_lines = [i for i in self.filtered_lines if start <= i <= end]
            self.update_preview()
            
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字")
    
    def update_preview(self):
        """更新代码预览区域"""
        self.preview_text.config(state=tk.NORMAL)
        self.preview_text.delete(1.0, tk.END)
        
        for i in self.filtered_lines:
            if i <= len(self.file_content):
                self.preview_text.insert(tk.END, self.file_content[i-1] + '\n')
        
        self.preview_text.config(state=tk.NORMAL)  # 保持可滚动但不可编辑
        
        # 更新状态栏
        self.status_var.set(f"总行数: {self.total_lines}, 当前选择: {len(self.filtered_lines)} 行")
        
        # 更新行号
        self.update_line_numbers()
    
    def select_all_lines(self):
        """全选所有行"""
        self.reset_filters()
    
    def on_ok(self):
        """确认选择"""
        if not self.filtered_lines:
            messagebox.showerror("错误", "没有选择任何行，请至少选择一行")
            return
            
        # 查找连续的行范围
        ranges = []
        start = self.filtered_lines[0]
        end = start
        
        for i in range(1, len(self.filtered_lines)):
            current = self.filtered_lines[i]
            if current == end + 1:
                end = current
            else:
                ranges.append((start, end))
                start = current
                end = current
        
        ranges.append((start, end))
        
        self.result = ranges
        self.destroy()
    
    def on_cancel(self):
        """取消选择"""
        self.result = None
        self.destroy()


class BatchFilterDialog(tk.Toplevel):
    def __init__(self, parent, title, all_files, template_file, template_path, template_content, project_path):
        super().__init__(parent)
        self.title(title)
        
        # 获取屏幕尺寸并设置窗口大小
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        
        # 窗口大小设为屏幕尺寸的80%，但确保最小尺寸
        window_width = max(700, int(screen_width * 0.8))
        window_height = max(500, int(screen_height * 0.8))
        
        # 设置窗口在屏幕中央
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 2
        
        self.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
        self.minsize(600, 400)  # 设置最小窗口大小
        
        # 允许调整大小
        self.resizable(True, True)
        
        self.result = {}  # 保存每个文件的过滤结果
        self.all_files = all_files
        self.template_file = template_file
        self.template_path = template_path
        self.template_content = template_content
        self.project_path = project_path
        self.filter_settings = {}  # 保存过滤设置
        self.processed_files = set()  # 已处理的文件
        
        # 创建主框架
        main_frame = ttk.Frame(self, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 显示模板文件信息
        ttk.Label(main_frame, text=f"使用模板文件: {template_file}").grid(
            row=0, column=0, columnspan=3, sticky=tk.W, pady=5)
        
        # 创建上下分割窗口
        paned = ttk.PanedWindow(main_frame, orient=tk.VERTICAL)
        paned.grid(row=1, column=0, columnspan=3, sticky=(tk.N, tk.S, tk.E, tk.W), pady=5)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(1, weight=1)
        
        # 上部过滤选项
        filter_frame = ttk.LabelFrame(paned, text="过滤设置")
        
        # 过滤选项
        filter_options_frame = ttk.Frame(filter_frame)
        filter_options_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 文件类型选择
        file_type_frame = ttk.Frame(filter_options_frame)
        file_type_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(file_type_frame, text="选择文件类型:").pack(side=tk.LEFT, padx=5)
        self.file_type_var = tk.StringVar()
        
        # 从所有文件中提取唯一的文件扩展名
        self.extensions = set()
        for file in all_files:
            _, ext = os.path.splitext(file)
            if ext:
                self.extensions.add(ext.lower())
        
        # 排序并添加扩展名
        extensions_list = ["全部"] + sorted(list(self.extensions))
        file_type_combo = ttk.Combobox(file_type_frame, textvariable=self.file_type_var, 
                                     values=extensions_list, state="readonly", width=15)
        file_type_combo.pack(side=tk.LEFT, padx=5)
        file_type_combo.current(0)  # 默认选择"全部"
        file_type_combo.bind("<<ComboboxSelected>>", self.filter_file_list)
        
        # 通用过滤选项
        common_filters_frame = ttk.Frame(filter_options_frame)
        common_filters_frame.pack(fill=tk.X, padx=5, pady=5)
        
        self.filter_imports_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(common_filters_frame, text="过滤导入语句", 
                      variable=self.filter_imports_var).grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        
        self.filter_empty_lines_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(common_filters_frame, text="过滤空白行", 
                      variable=self.filter_empty_lines_var).grid(row=0, column=1, sticky=tk.W, padx=5, pady=2)
        
        self.filter_comments_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(common_filters_frame, text="过滤注释", 
                      variable=self.filter_comments_var).grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
        
        # 特定文件类型过滤选项
        special_filters_frame = ttk.Frame(filter_options_frame)
        special_filters_frame.pack(fill=tk.X, padx=5, pady=5)
        
        self.filter_annotations_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(special_filters_frame, text="过滤注解(@开头)", 
                      variable=self.filter_annotations_var).grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        
        self.filter_html_head_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(special_filters_frame, text="过滤HTML头部", 
                      variable=self.filter_html_head_var).grid(row=0, column=1, sticky=tk.W, padx=5, pady=2)
        
        self.filter_keep_main_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(special_filters_frame, text="只保留主要内容", 
                      variable=self.filter_keep_main_var).grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
        
        # 自定义过滤
        custom_filter_frame = ttk.Frame(filter_options_frame)
        custom_filter_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(custom_filter_frame, text="自定义过滤正则表达式:").pack(side=tk.LEFT, padx=5)
        self.custom_regex_var = tk.StringVar()
        self.custom_regex_entry = ttk.Entry(custom_filter_frame, textvariable=self.custom_regex_var, width=30)
        self.custom_regex_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        # 过滤操作按钮
        filter_buttons_frame = ttk.Frame(filter_frame)
        filter_buttons_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(filter_buttons_frame, text="智能检测核心代码", 
                 command=self.auto_detect_core_code).pack(side=tk.LEFT, padx=5)
        ttk.Button(filter_buttons_frame, text="预览当前设置", 
                 command=self.preview_settings).pack(side=tk.LEFT, padx=5)
        ttk.Button(filter_buttons_frame, text="重置过滤设置", 
                 command=self.reset_filters).pack(side=tk.LEFT, padx=5)
        
        # 添加过滤框架到分割窗口
        paned.add(filter_frame, weight=1)
        
        # 中部文件列表
        file_frame = ttk.LabelFrame(paned, text="选择要应用过滤的文件")
        
        # 添加全选复选框
        select_all_frame = ttk.Frame(file_frame)
        select_all_frame.pack(fill=tk.X, padx=5, pady=2)
        
        self.select_all_var = tk.BooleanVar(value=False)
        select_all_cb = ttk.Checkbutton(select_all_frame, text="全选/取消全选", 
                                     variable=self.select_all_var,
                                     command=self.toggle_all_files)
        select_all_cb.pack(side=tk.LEFT, padx=5)
        
        # 添加选择计数标签
        self.selection_count_var = tk.StringVar(value="已选择: 0")
        ttk.Label(select_all_frame, textvariable=self.selection_count_var).pack(side=tk.LEFT, padx=5)
        
        file_list_frame = ttk.Frame(file_frame)
        file_list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 添加文件列表
        scrollbar = ttk.Scrollbar(file_list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.file_listbox = tk.Listbox(file_list_frame, selectmode=tk.MULTIPLE)
        self.file_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.file_listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.file_listbox.yview)
        
        # 添加选择按钮
        file_buttons_frame = ttk.Frame(file_frame)
        file_buttons_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(file_buttons_frame, text="全选", 
                 command=self.select_all_files).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_buttons_frame, text="取消全选", 
                 command=self.deselect_all_files).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_buttons_frame, text="根据类型选择", 
                 command=self.select_by_type).pack(side=tk.LEFT, padx=5)
        
        # 添加文件框架到分割窗口
        paned.add(file_frame, weight=2)
        
        # 下部预览区域
        preview_frame = ttk.LabelFrame(paned, text="过滤结果预览")
        
        # 添加过滤后文件数量的标签
        self.filtered_count_var = tk.StringVar(value="已选择 0 个文件，0 个文件将应用过滤")
        ttk.Label(preview_frame, textvariable=self.filtered_count_var).pack(fill=tk.X, padx=5, pady=5)
        
        preview_buttons_frame = ttk.Frame(preview_frame)
        preview_buttons_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(preview_buttons_frame, text="应用到选中文件", 
                 command=self.apply_to_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(preview_buttons_frame, text="预览选中文件", 
                 command=self.preview_selected).pack(side=tk.LEFT, padx=5)
        
        self.preview_text = ScrolledText(preview_frame, wrap=tk.NONE, height=10)
        self.preview_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 添加预览框架到分割窗口
        paned.add(preview_frame, weight=2)
        
        # 状态栏
        self.status_var = tk.StringVar(value="准备就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.grid(row=2, column=0, columnspan=3, sticky=(tk.E, tk.W), pady=5)
        
        # 底部按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=3, column=0, columnspan=3, pady=10)
        
        ttk.Button(button_frame, text="应用到所有选中文件", 
                 command=self.apply_to_all).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="确定", 
                 command=self.on_ok).pack(side=tk.RIGHT, padx=5)
        ttk.Button(button_frame, text="取消", 
                 command=self.on_cancel).pack(side=tk.RIGHT, padx=5)
        
        # 填充文件列表
        self.filtered_files = self.all_files.copy()
        self.update_file_list()
        
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.on_cancel)
    
    def filter_file_list(self, event=None):
        """按文件类型过滤文件列表"""
        selected_type = self.file_type_var.get()
        
        if selected_type == "全部":
            self.filtered_files = self.all_files.copy()
        else:
            self.filtered_files = [file for file in self.all_files 
                                if file.lower().endswith(selected_type)]
        
        self.update_file_list()
    
    def update_file_list(self):
        """更新文件列表显示"""
        self.file_listbox.delete(0, tk.END)
        
        for file in self.filtered_files:
            item_text = file
            if file in self.processed_files:
                item_text = "✓ " + item_text
            self.file_listbox.insert(tk.END, item_text)
        
        # 更新过滤计数
        selected_count = len(self.file_listbox.curselection())
        self.selection_count_var.set(f"已选择: {selected_count}")
        self.filtered_count_var.set(f"显示 {len(self.filtered_files)} 个文件，选择 {selected_count} 个")
    
    def select_all_files(self):
        """全选所有文件"""
        self.file_listbox.select_set(0, tk.END)
        self.select_all_var.set(True)
        selected_count = len(self.file_listbox.curselection())
        self.selection_count_var.set(f"已选择: {selected_count}")
        self.filtered_count_var.set(f"显示 {len(self.filtered_files)} 个文件，选择 {selected_count} 个")
    
    def deselect_all_files(self):
        """取消全选"""
        self.file_listbox.selection_clear(0, tk.END)
        self.select_all_var.set(False)
        self.selection_count_var.set("已选择: 0")
        self.filtered_count_var.set(f"显示 {len(self.filtered_files)} 个文件，选择 0 个")
    
    def select_by_type(self):
        """根据当前选择的类型选择文件"""
        selected_type = self.file_type_var.get()
        if selected_type == "全部":
            self.select_all_files()
            return
        
        # 清除当前选择
        self.file_listbox.selection_clear(0, tk.END)
        
        # 根据类型选择
        count = 0
        for i, file in enumerate(self.filtered_files):
            if file.lower().endswith(selected_type):
                self.file_listbox.selection_set(i)
                count += 1
        
        # 更新全选状态
        self.select_all_var.set(count == len(self.filtered_files))
        
        # 更新计数
        self.selection_count_var.set(f"已选择: {count}")
        self.filtered_count_var.set(f"显示 {len(self.filtered_files)} 个文件，选择 {count} 个")
    
    def auto_detect_core_code(self):
        """自动设置核心代码过滤选项"""
        # 根据模板文件类型设置合适的过滤选项
        _, ext = os.path.splitext(self.template_path)
        ext = ext.lower()
        
        # 重置过滤
        self.reset_filters()
        
        # 应用基本过滤
        self.filter_imports_var.set(True)
        self.filter_empty_lines_var.set(True)
        
        # 文件类型特定处理
        if ext in ['.java', '.kt', '.scala', '.cs']:
            self.filter_annotations_var.set(True)
            self.filter_comments_var.set(True)
        
        elif ext in ['.html', '.vue', '.jsx', '.tsx']:
            self.filter_html_head_var.set(True)
            self.filter_keep_main_var.set(True)
        
        self.status_var.set(f"已为 {ext} 文件类型自动设置过滤选项")
    
    def reset_filters(self):
        """重置所有过滤设置"""
        self.filter_imports_var.set(False)
        self.filter_empty_lines_var.set(False)
        self.filter_comments_var.set(False)
        self.filter_annotations_var.set(False)
        self.filter_html_head_var.set(False)
        self.filter_keep_main_var.set(False)
        self.custom_regex_var.set("")
        
        self.status_var.set("已重置所有过滤设置")
    
    def get_current_filter_settings(self):
        """获取当前过滤设置"""
        settings = {
            'filter_imports': self.filter_imports_var.get(),
            'filter_empty_lines': self.filter_empty_lines_var.get(),
            'filter_comments': self.filter_comments_var.get(),
            'filter_annotations': self.filter_annotations_var.get(),
            'filter_html_head': self.filter_html_head_var.get(),
            'filter_keep_main': self.filter_keep_main_var.get(),
            'custom_regex': self.custom_regex_var.get()
        }
        return settings
    
    def preview_settings(self):
        """预览当前设置效果"""
        # 使用当前设置过滤模板文件
        settings = self.get_current_filter_settings()
        template_lines = self.template_content.split('\n')
        filtered_line_numbers = self.apply_filters_to_content(template_lines, self.template_path, settings)
        
        # 显示预览
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.insert(tk.END, f"预览模板文件: {self.template_file}\n")
        self.preview_text.insert(tk.END, f"过滤前行数: {len(template_lines)}, ")
        self.preview_text.insert(tk.END, f"过滤后行数: {len(filtered_line_numbers)}\n\n")
        
        # 添加过滤后的前20行作为预览
        preview_lines = filtered_line_numbers[:20]
        for i, line_num in enumerate(preview_lines):
            if line_num <= len(template_lines):
                self.preview_text.insert(tk.END, f"{line_num}: {template_lines[line_num-1]}\n")
        
        if len(filtered_line_numbers) > 20:
            self.preview_text.insert(tk.END, "...\n")
        
        self.status_var.set(f"已预览当前过滤设置，保留了 {len(filtered_line_numbers)}/{len(template_lines)} 行")
    
    def preview_selected(self):
        """预览选中文件的过滤效果"""
        selected_indices = self.file_listbox.curselection()
        if not selected_indices:
            messagebox.showwarning("警告", "请选择要预览的文件")
            return
        
        # 获取选中的第一个文件
        index = selected_indices[0]
        if index >= len(self.filtered_files):
            return
            
        file_path = self.filtered_files[index]
        full_path = os.path.join(self.project_path, file_path)
        
        try:
            with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
                content = f.read()
        except Exception as e:
            messagebox.showerror("错误", f"无法读取文件 {file_path}: {str(e)}")
            return
        
        # 使用当前设置过滤
        settings = self.get_current_filter_settings()
        content_lines = content.split('\n')
        filtered_line_numbers = self.apply_filters_to_content(content_lines, full_path, settings)
        
        # 显示预览
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.insert(tk.END, f"预览文件: {file_path}\n")
        self.preview_text.insert(tk.END, f"过滤前行数: {len(content_lines)}, ")
        self.preview_text.insert(tk.END, f"过滤后行数: {len(filtered_line_numbers)}\n\n")
        
        # 添加过滤后的前20行作为预览
        preview_line_numbers = filtered_line_numbers[:20]
        for i, line_num in enumerate(preview_line_numbers):
            if line_num <= len(content_lines):
                self.preview_text.insert(tk.END, f"{line_num}: {content_lines[line_num-1]}\n")
        
        if len(filtered_line_numbers) > 20:
            self.preview_text.insert(tk.END, "...\n")
        
        self.status_var.set(f"已预览文件 {file_path}，保留了 {len(filtered_line_numbers)}/{len(content_lines)} 行")
    
    def apply_filters_to_content(self, content_lines, file_path, settings):
        """应用过滤设置到内容，返回保留的行号"""
        # 初始包含所有行
        filtered_line_numbers = list(range(1, len(content_lines) + 1))
        lines_content = {i+1: line for i, line in enumerate(content_lines)}
        
        # 应用过滤
        if settings['filter_imports']:
            filtered_line_numbers = self.filter_imports(filtered_line_numbers, lines_content)
        
        if settings['filter_empty_lines']:
            filtered_line_numbers = self.filter_empty_lines(filtered_line_numbers, lines_content)
        
        if settings['filter_comments']:
            filtered_line_numbers = self.filter_comments(filtered_line_numbers, lines_content, file_path)
        
        if settings['filter_annotations']:
            filtered_line_numbers = self.filter_annotations(filtered_line_numbers, lines_content)
        
        if settings['filter_html_head']:
            filtered_line_numbers = self.filter_html_head(filtered_line_numbers, lines_content)
        
        if settings['filter_keep_main']:
            filtered_line_numbers = self.filter_keep_main_content(filtered_line_numbers, lines_content, file_path)
        
        # 应用自定义正则
        custom_regex = settings['custom_regex'].strip()
        if custom_regex:
            try:
                pattern = re.compile(custom_regex)
                filtered_line_numbers = [i for i in filtered_line_numbers 
                                if i <= len(content_lines) and not pattern.search(lines_content[i])]
            except re.error:
                pass
        
        # 按行号排序
        filtered_line_numbers.sort()
        
        # 返回过滤后的行号列表
        return filtered_line_numbers
    
    def filter_imports(self, line_indices, lines_content):
        """过滤导入语句"""
        import_patterns = [
            r'^\s*import\s+', 
            r'^\s*from\s+.+\s+import\s+',
            r'^\s*require\s*\(',
            r'^\s*#include\s+',
            r'^\s*using\s+',
            r'^\s*@import\s+'
        ]
        combined_pattern = re.compile('|'.join(import_patterns))
        
        return [i for i in line_indices 
              if i > len(lines_content) or not combined_pattern.match(lines_content[i])]
    
    def filter_empty_lines(self, line_indices, lines_content):
        """过滤空白行"""
        return [i for i in line_indices 
              if i > len(lines_content) or lines_content[i].strip()]
    
    def filter_comments(self, line_indices, lines_content, file_path):
        """过滤注释"""
        # 处理多种语言的注释格式
        comment_patterns = [
            r'^\s*\/\/.*$',  # Java, JavaScript等单行注释
            r'^\s*#.*$',     # Python, Shell等单行注释
            r'^\s*--.*$',    # SQL, Lua等单行注释
            r'^\s*\/\*.*\*\/\s*$', # 单行多行注释
            r'^\s*\*.*$'     # 多行注释的中间行
        ]
        combined_pattern = re.compile('|'.join(comment_patterns))
        
        # 找出所有多行注释的行
        in_multiline_comment = False
        multiline_comment_lines = set()
        
        for i in range(1, len(lines_content) + 1):
            line = lines_content.get(i, "")
            if re.search(r'\/\*', line) and not re.search(r'\*\/', line):
                in_multiline_comment = True
                multiline_comment_lines.add(i)
            elif in_multiline_comment:
                multiline_comment_lines.add(i)
                if re.search(r'\*\/', line):
                    in_multiline_comment = False
        
        return [i for i in line_indices 
              if i > len(lines_content) 
              or (not combined_pattern.match(lines_content[i]) and i not in multiline_comment_lines)]
    
    def filter_annotations(self, line_indices, lines_content):
        """过滤Java注解等"""
        annotation_pattern = re.compile(r'^\s*@\w+')
        return [i for i in line_indices 
              if i > len(lines_content) or not annotation_pattern.match(lines_content[i])]
    
    def filter_html_head(self, line_indices, lines_content):
        """过滤HTML/Vue头部"""
        if not any('<head>' in lines_content.get(i, "") for i in range(1, len(lines_content) + 1)):
            return line_indices
            
        in_head = False
        head_lines = set()
        
        for i in range(1, len(lines_content) + 1):
            line = lines_content.get(i, "")
            if '<head>' in line:
                in_head = True
                head_lines.add(i)
            elif in_head:
                head_lines.add(i)
                if '</head>' in line:
                    in_head = False
        
        return [i for i in line_indices if i not in head_lines]
    
    def filter_keep_main_content(self, line_indices, lines_content, file_path):
        """只保留主要内容区域"""
        _, ext = os.path.splitext(file_path)
        ext = ext.lower()
        
        if ext == '.vue':
            # Vue文件尝试保留template部分
            in_template = False
            keep_lines = set()
            
            for i in range(1, len(lines_content) + 1):
                line = lines_content.get(i, "")
                if '<template>' in line:
                    in_template = True
                    keep_lines.add(i)
                elif in_template:
                    keep_lines.add(i)
                    if '</template>' in line:
                        in_template = False
            
            if keep_lines:
                return [i for i in line_indices if i in keep_lines]
        
        elif ext in ['.html', '.jsx', '.tsx']:
            # 尝试找到主体内容
            body_pattern = re.compile(r'<body.*?>|<div.*?id="app"|<div.*?class="container"|class="main"')
            end_pattern = re.compile(r'</body>|</div>')
            
            in_main_content = False
            main_content_start = 0
            keep_lines = set()
            
            for i in range(1, len(lines_content) + 1):
                line = lines_content.get(i, "")
                if not in_main_content and body_pattern.search(line):
                    in_main_content = True
                    main_content_start = i
                    keep_lines.add(i)
                elif in_main_content:
                    keep_lines.add(i)
                    if end_pattern.search(line) and i - main_content_start > 5:  # 确保不是小div
                        in_main_content = False
            
            if keep_lines:
                return [i for i in line_indices if i in keep_lines]
        
        return line_indices
    
    def apply_to_selected(self):
        """应用当前过滤设置到选中的文件"""
        selected_indices = self.file_listbox.curselection()
        if not selected_indices:
            messagebox.showwarning("警告", "请选择要应用过滤的文件")
            return
        
        settings = self.get_current_filter_settings()
        self.filter_settings = settings  # 保存设置以供后续使用
        
        processed_count = 0
        for index in selected_indices:
            if index >= len(self.filtered_files):
                continue
                
            file_path = self.filtered_files[index]
            full_path = os.path.join(self.project_path, file_path)
            
            try:
                with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
                    content = f.read()
            except Exception as e:
                messagebox.showerror("错误", f"无法读取文件 {file_path}: {str(e)}")
                continue
            
            # 应用过滤，获取保留的行号
            content_lines = content.split('\n')
            filtered_line_numbers = self.apply_filters_to_content(content_lines, full_path, settings)
            
            # 找出连续行范围
            if filtered_line_numbers:
                ranges = self.find_continuous_ranges(filtered_line_numbers)
                self.result[file_path] = ranges
                self.processed_files.add(file_path)
                processed_count += 1
        
        # 更新文件列表显示
        self.update_file_list()
        self.status_var.set(f"已应用过滤到 {processed_count} 个文件")
    
    def apply_to_all(self):
        """应用过滤设置到所有选中的文件"""
        # 获取当前过滤设置
        settings = self.get_current_filter_settings()
        self.filter_settings = settings
        
        # 处理所有选中文件
        processed_count = 0
        for index in range(len(self.filtered_files)):
            file_path = self.filtered_files[index]
            full_path = os.path.join(self.project_path, file_path)
            
            try:
                with open(full_path, 'r', encoding='utf-8', errors='replace') as f:
                    content = f.read()
            except Exception as e:
                continue
            
            # 应用过滤，获取保留的行号
            content_lines = content.split('\n')
            filtered_line_numbers = self.apply_filters_to_content(content_lines, full_path, settings)
            
            # 找出连续行范围
            if filtered_line_numbers:
                ranges = self.find_continuous_ranges(filtered_line_numbers)
                self.result[file_path] = ranges
                self.processed_files.add(file_path)
                processed_count += 1
        
        # 更新文件列表显示
        self.update_file_list()
        messagebox.showinfo("完成", f"已应用过滤到 {processed_count} 个文件")
        self.status_var.set(f"已应用过滤到所有 {processed_count} 个文件")
    
    def find_continuous_ranges(self, line_numbers):
        """找出连续的行号范围"""
        if not line_numbers:
            return []
            
        ranges = []
        start = line_numbers[0]
        end = start
        
        for i in range(1, len(line_numbers)):
            current = line_numbers[i]
            if current == end + 1:
                end = current
            else:
                ranges.append((start, end))
                start = current
                end = current
        
        ranges.append((start, end))
        return ranges
    
    def on_ok(self):
        """确认选择"""
        if not self.result:
            if messagebox.askyesno("确认", "当前没有处理任何文件，是否继续？"):
                self.destroy()
        else:
            self.destroy()
    
    def on_cancel(self):
        """取消选择"""
        self.result = {}
        self.destroy()
    
    def toggle_all_files(self):
        """根据全选复选框状态全选或取消全选所有文件"""
        if self.select_all_var.get():
            self.file_listbox.select_set(0, tk.END)
        else:
            self.file_listbox.selection_clear(0, tk.END)
        
        # 更新选择计数
        selected_count = len(self.file_listbox.curselection())
        self.selection_count_var.set(f"已选择: {selected_count}")
        self.filtered_count_var.set(f"显示 {len(self.filtered_files)} 个文件，选择 {selected_count} 个")


class ExportOptionsDialog(tk.Toplevel):
    def __init__(self, parent, title):
        super().__init__(parent)
        self.title(title)
        
        # 获取屏幕尺寸并设置窗口大小
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        
        # 使用较小的窗口，适合对话框
        window_width = min(400, int(screen_width * 0.5))
        window_height = min(350, int(screen_height * 0.5))
        
        # 设置窗口在屏幕中央
        x_position = (screen_width - window_width) // 2
        y_position = (screen_height - window_height) // 2
        
        self.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")
        
        # 允许调整大小
        self.resizable(True, True)
        
        self.confirmed = False
        self.options = {}
        
        # 默认选项
        self.include_header_var = tk.BooleanVar(value=True)
        self.include_filenames_var = tk.BooleanVar(value=True)
        self.include_code_blocks_var = tk.BooleanVar(value=True)
        self.include_separators_var = tk.BooleanVar(value=False)  # 默认不包含分隔符
        
        # 创建选项界面
        frame = ttk.Frame(self, padding="10")
        frame.pack(fill=tk.BOTH, expand=True)
        
        ttk.Label(frame, text="请选择导出选项:").grid(row=0, column=0, sticky=tk.W, pady=10)
        
        # 选项复选框
        ttk.Checkbutton(frame, text="包含标题 (# 源代码附录)", 
                      variable=self.include_header_var).grid(row=1, column=0, sticky=tk.W, pady=2)
        
        ttk.Checkbutton(frame, text="包含文件名 (## filename.ext)", 
                      variable=self.include_filenames_var).grid(row=2, column=0, sticky=tk.W, pady=2)
        
        ttk.Checkbutton(frame, text="包含代码块标记 (```)", 
                      variable=self.include_code_blocks_var).grid(row=3, column=0, sticky=tk.W, pady=2)
        
        ttk.Checkbutton(frame, text="包含分隔符 (// ...)", 
                      variable=self.include_separators_var).grid(row=4, column=0, sticky=tk.W, pady=2)
        
        # 预览
        ttk.Label(frame, text="预览:").grid(row=5, column=0, sticky=tk.W, pady=5)
        
        preview_frame = ttk.Frame(frame, relief=tk.SUNKEN, padding=5)
        preview_frame.grid(row=6, column=0, sticky=(tk.W, tk.E), pady=5)
        
        self.preview_text = tk.Text(preview_frame, height=8, wrap=tk.WORD)
        self.preview_text.pack(fill=tk.BOTH, expand=True)
        self.update_preview()
        
        # 绑定事件更新预览
        self.include_header_var.trace_add("write", lambda *args: self.update_preview())
        self.include_filenames_var.trace_add("write", lambda *args: self.update_preview())
        self.include_code_blocks_var.trace_add("write", lambda *args: self.update_preview())
        self.include_separators_var.trace_add("write", lambda *args: self.update_preview())
        
        # 按钮
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=7, column=0, pady=10)
        
        ttk.Button(button_frame, text="确定", command=self.on_ok).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="取消", command=self.on_cancel).pack(side=tk.LEFT, padx=5)
        
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.on_cancel)
    
    def update_preview(self):
        """更新预览内容"""
        self.preview_text.delete(1.0, tk.END)
        
        preview = ""
        if self.include_header_var.get():
            preview += "# 源代码附录\n\n"
        
        if self.include_filenames_var.get():
            preview += "## example.java\n\n"
        
        if self.include_code_blocks_var.get():
            preview += "```\n"
        
        preview += "public class Example {\n    public static void main(String[] args) {\n        System.out.println(\"Hello\");\n    }\n"
        
        if self.include_separators_var.get():
            preview += "\n// ...\n\n"
        
        preview += "    public void anotherMethod() {\n        // 方法实现\n    }\n"
        
        if self.include_code_blocks_var.get():
            preview += "```\n"
        
        self.preview_text.insert(1.0, preview)
    
    def on_ok(self):
        """确认选择"""
        self.confirmed = True
        self.options = {
            'include_header': self.include_header_var.get(),
            'include_filenames': self.include_filenames_var.get(),
            'include_code_blocks': self.include_code_blocks_var.get(),
            'include_separators': self.include_separators_var.get()
        }
        self.destroy()
    
    def on_cancel(self):
        """取消选择"""
        self.confirmed = False
        self.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = CodeExportTool(root)
    root.mainloop() 